#pragma once

#ifndef _CORE_SERVER_CONNECTION_H_
#define _CORE_SERVER_CONNECTION_H_

#include "Poco\Runnable.h"
#include "Poco\Delegate.h"
#include "Poco\Event.h"
#include "Poco\ThreadPool.h"
#include "Poco\Thread.h"
#include "Poco\SharedPtr.h"
#include "Poco\Timer.h"
#include "Poco\BasicEvent.h"
#include "Poco\Net\StreamSocket.h"
#include "Poco\Net\SocketReactor.h"
#include "Poco\Net\TCPServer.h"
#include "Poco\Net\ServerSocket.h"
#include "Poco\Net\ServerSocket.h"

#include "Core\SafeMutex.h"

namespace ExamSystem
{
    using Poco::SharedPtr;
    using Poco::Thread;
    using Poco::ThreadPool;
    using Poco::Runnable;
    using Poco::Timer;
    using Poco::TimerCallback;
    using Poco::BasicEvent;
    using Poco::Net::StreamSocket;
    using Poco::Net::ServerSocket;
    using Poco::Net::TCPServer;
    
    class CXMLConnection;
    class CCoreXMLHandlerManager;

    /**************************************************************************\
     Component:     CExamServerConnectionManager
     Description:   
        This class manages all connected sockets.
        1. It will send keep-alive package to each connection every 15s. If any
           socket doesn't reply, the manager will disconnect it.
        2. It will check each received package. If the package is not a keep-alive
           replay, the manager will emit a signal.
    \**************************************************************************/
    class CExamServerConnectionManager
    {
    public:
        CExamServerConnectionManager(void);
        ~CExamServerConnectionManager(void);

    public:

    public:
        enum { MaxConnectedClient = 500 };

    public:
        // start server
        // this function will run a TCPServer on another thread
        void StartServer(void);
        // stop the server and disconnect all 
        void StopServer(void);

        // register a connection to this manager
        void ManageConnection(const StreamSocket &s);

        // return the xml handler manager
        SharedPtr<CCoreXMLHandlerManager> &GetHandlerManager(void);
        const SharedPtr<CCoreXMLHandlerManager> &GetHandlerManager(void) const;

        // set the listening port. This must be set BEFORE running the server
        void SetPort(unsigned int port);

        // get the xml connection
        const SharedPtr<CXMLConnection> &GetXMLConnection(int id);

        // get server listening address
        std::string GetListenAddress(void) const;

    public:
        // events
        BasicEvent<int> eventConnectionClosed;

    protected:
        // event handlers
        void OnConnectionClosed(const void* pSender, int &id);

        // timer call backs
        void OnKeepAliveTimer(Timer &timer);
        // send keep alive package to all connected clients
        void SendKeepAlivePackages(void);
        // check keep alive replies, if any connection doesn't reply, we will disconnect it.
        void CheckKeepAliveReplies(void);

    protected:
        // all connections
        std::vector<SharedPtr<CXMLConnection> > m_managedConnections;
        // closed connection that will be deleted later
        SharedPtr<CXMLConnection> m_closedConnection;
        // a lock for m_managedConnections
        CSafeMutex m_lockConnectionManager;

        // a thread pool. when a new connection comes, we will assign a new thread for it
        ThreadPool m_threadPool;

        // the common xml handlers
        SharedPtr<CCoreXMLHandlerManager> m_xmlHandlerManager;

        // server staff
        SharedPtr<TCPServer> m_tcpServer;
        SharedPtr<ServerSocket> m_serverSocket;
        unsigned int m_port;

        // timer
        Timer m_keepAliveTimer;
        int m_keepAliveTimerCount;
        TimerCallback<CExamServerConnectionManager> m_keepAliveTimerCallback;

        // if the server is running
        CSafeMutex m_lockServerRunningFlag;
        bool m_flagServerRunning;
    };

}

#endif